Skip to content

Add detail_level and max_flows to get_affected_flows (fixes #849) - #853

Merged
tirth8205 merged 2 commits into
tirth8205:mainfrom
asemraza:feat/affected-flows-detail-level
Aug 19, 2026
Merged

Add detail_level and max_flows to get_affected_flows (fixes #849)#853
tirth8205 merged 2 commits into
tirth8205:mainfrom
asemraza:feat/affected-flows-detail-level

Conversation

@asemraza

Copy link
Copy Markdown
Contributor

Fixes #849

Problem

get_affected_flows_tool is step 2 of the documented review-pr workflow with its <=800-token target, but it was the only tool in the chain without detail_level and had no result bound. Each flow embeds a full steps list, so a 75-file change set produced a 247k-token response.

Change

  • detail_level="minimal": per-flow metadata only (id, name, criticality, depth, node_count, file_count), same convention as the sibling tools.
  • max_flows (default 50, 0 disables): bounds the returned list. total always reports the untruncated count and truncated flags the cut, mirroring the impact-radius truncation contract. The summary appends "showing N" when truncated.

Both parameters are wired through the MCP tool wrapper with updated docstrings.

Tests

Three new tests: minimal drops steps/path, max_flows truncates with correct total/truncated/summary, max_flows=0 disables the limit. Full suite 2,401 passed, ruff and mypy clean.

get_affected_flows_tool was the only tool in the review chain without
detail_level, and it had no result bound. Every flow carries a full
steps list, so a 75-file change set returned a 247k-token response in
the middle of the documented minimal-first workflow.

detail_level="minimal" strips flows to per-flow metadata (name,
criticality, depth, counts). max_flows bounds the list (default 50,
0 disables); total always reports the untruncated count and truncated
flags the cut, mirroring the impact-radius truncation contract.

Fixes tirth8205#849
@github-actions

Copy link
Copy Markdown

code-review-graph review

Overall risk: 0.54 (MEDIUM) — 6 changed function(s)/class(es), 0 affected flow(s), 3 test gap(s)

Risk-scored changes

Risk Level Symbol Location Tested
0.54 medium code_review_graph/main.py::get_affected_flows_tool code_review_graph/main.py:529 no
0.30 low code_review_graph/tools/review.py::get_affected_flows_func code_review_graph/tools/review.py:292 no
0.05 low tests/test_tools.py::TestFlowTools tests/test_tools.py:1061 no
0.05 low tests/test_tools.py::TestFlowTools.test_get_affected_flows_minimal_drops_steps tests/test_tools.py:1269 (test)
0.05 low tests/test_tools.py::TestFlowTools.test_get_affected_flows_max_flows_truncates tests/test_tools.py:1284 (test)
0.05 low tests/test_tools.py::TestFlowTools.test_get_affected_flows_max_flows_zero_disables_limit tests/test_tools.py:1297 (test)

Test gaps

  • code_review_graph/main.py::get_affected_flows_tool (code_review_graph/main.py:529)
  • code_review_graph/tools/review.py::get_affected_flows_func (code_review_graph/tools/review.py:292)
  • tests/test_tools.py::TestFlowTools (tests/test_tools.py:1061)

Token savings: this graph-backed report used ~37,860 fewer tokens (~96%) than reading every changed file in full (estimated, chars/4 approximation).


Powered by code-review-graph — local-first analysis; no code leaves the CI runner.

@tirth8205

Copy link
Copy Markdown
Owner

Matches the sibling tool conventions and the truncation contract, and the 60 flow default cap case checks out. Merging. Follow-up noted in #866: the no changed files early return in tools/review.py omits the new truncated key.

@tirth8205
tirth8205 merged commit a85f323 into tirth8205:main Aug 19, 2026
13 checks passed
TFSebben pushed a commit to TFSebben/code-review-graph that referenced this pull request Aug 19, 2026
tirth8205#849 found get_affected_flows returning ~247k tokens inside a workflow
documented as "5 tool calls, 800 tokens total". PR tirth8205#853 capped that one
tool. Measuring all 30 registered tools against a real 5.6k-node graph
found the same class of bug in ten more places, several of them on the
default path:

  list_communities            206,858 tokens with DEFAULT arguments
  get_community               134,781 default / 535,618 with members
  get_architecture_overview   625,012 in standard mode
  refactor dead_code           47,312 / suggest 38,246
  detect_changes               46,089 for a ONE-file diff
  get_surprising_connections 1,287,174 at top_n=10**6
  get_hub_nodes              555,848 / get_bridge_nodes 317,202
  get_review_context        4,720,622 on a whole-repo diff

PR tirth8205#853's own fix was also only half a fix: standard mode carries a full
steps list per flow (~980 tokens each), so its 50-flow cap still produced
~49k tokens, and max_flows=0 disabled the limit entirely.

Every list-returning tool now follows one contract, the one tirth8205#853
established: `total` (or a per-list `*_total`) always reports the
untruncated count, `truncated` marks the cut, and the summary line says
how many of how many are shown. Bounds are validated the way query.py
validates max_results - booleans rejected, values below 1 rejected.
detail_level="minimal" was added to the analysis and refactor tools,
projecting to the same compact field sets their siblings use.

Where a count alone cannot bound a response, a shared budget does:
get_flow and get_affected_flows spend a step budget, get_review_context
and detect_changes spend a source-line budget. Ceilings that depend on
payload size depend on detail_level, mirroring query.py capping
minimal-mode results at five.

Two behaviour changes are deliberate and their tirth8205#853 tests are updated in
this commit: get_affected_flows standard mode now caps at 25 flows
(minimal at 500), and max_flows=0 keeps its "no caller limit" meaning
while still obeying the ceiling - an escape hatch that returns a quarter
of a million tokens is the bug, not a feature.

Default behaviour stays backward compatible in shape: an existing caller
passing nothing still gets a valid response, just bounded.

tests/test_token_budget.py records the measured budget table as
reviewable data and pins it three ways: per-tool default and worst-case
token ceilings, exact truncated list lengths against the imported
ceiling constants, and the ceiling constants themselves. Removing a cap,
raising a ceiling, or adding an unbounded field fails it. The fixture
graph builds once per module and the whole file runs in ~7s, offline.

Reported, not fixed: code_review_graph/tools/query.py is owned elsewhere
and four of its tools remain unbounded - get_impact_radius (3.4M tokens;
changed_nodes and edges ignore max_results, which is not even exposed on
the MCP signature), find_large_functions (737k), traverse_graph (385k)
and semantic_search_nodes, whose limit/token_budget are neither
validated nor capped. Their default budgets are still asserted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fHfGDiZedoxjpKzanHri3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

get_affected_flows_tool has no detail_level or limit parameter and returns 247k+ tokens, breaking the documented token budget

2 participants